package com.block.merchant.service.datapush;

import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.block.common.enums.InfoTypeEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.service.LogFactory;
import com.block.datapush.model.result.FilterHandlerResult;
import com.block.datapush.service.IDataFilterHandleService;
import com.block.db.entity.MemberSourceInfo;
import com.block.db.entity.MerchantTaskInfo;
import com.block.db.mapper.MerchantTaskInfoMapper;
import com.block.merchant.model.dto.MerchantOrderDTO;
import com.block.merchant.model.result.DataMatchResult;
import com.block.merchant.model.result.MatchMerchantInfo;
import com.block.merchant.service.IDataMerchantPushService;
import com.block.merchant.service.IMerchantBaseInfoService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class DataMerchantPushService implements IDataMerchantPushService {

    private static final Logger log = LogFactory.getMerchantLog();

    @Autowired
    NotifyExceptionService notifyExceptionService;
    @Autowired
    IMerchantBaseInfoService merchantBaseInfoService;
    @Resource
    MerchantTaskInfoMapper merchantTaskInfoMapper;
    @Autowired
    IDataFilterHandleService dataFilterHandleService;

    /**
     * 数据匹配结果
     *
     * @param memberSourceInfo
     * @return
     */
    @Override
    public DataMatchResult dataMatchHandle(MemberSourceInfo memberSourceInfo) {

        DataMatchResult dataMatchResult = new DataMatchResult();
        dataMatchResult.setUid(memberSourceInfo.getUid());

        List<MatchMerchantInfo> merchantInfoList = this.getApiAndCrmPushInfo1(memberSourceInfo);


        if (merchantInfoList.size()>0){
            MatchMerchantInfo matchMerchantInfo = merchantInfoList.get(0);
            // 判断机构是否为单推
            // 如果为单推，则取该值唯一返回
            if (ObjectUtil.equals(matchMerchantInfo.getSinglePushFlag(), Integer.valueOf(0))){
                merchantInfoList = Arrays.asList(matchMerchantInfo);
            }
        }

        dataMatchResult.setMerchantInfoList(merchantInfoList);
        dataMatchResult.setMatchSize(merchantInfoList.size());
        return dataMatchResult;
    }


    @Override
    public DataMatchResult dataMatchApiBHandle(MemberSourceInfo memberSourceInfo) {

        DataMatchResult dataMatchResult = new DataMatchResult();
        dataMatchResult.setUid(memberSourceInfo.getUid());

        List<MatchMerchantInfo> merchantInfoList = this.getApiBPushInfo(memberSourceInfo);

        dataMatchResult.setMerchantInfoList(merchantInfoList);
        dataMatchResult.setMatchSize(merchantInfoList.size());
        return dataMatchResult;
    }

    /**
     * 获取APIB 的推送订单信息
     */
    public List<MatchMerchantInfo> getApiBPushInfo(MemberSourceInfo memberSourceInfo) {

        List<MatchMerchantInfo> merchantInfoList = new ArrayList<>();
        try {

            List<MerchantTaskInfo> resultTaskList = new ArrayList<>();
            Set<Integer> canMatchMerchantSet = new HashSet<>();// 过滤同一个商户的作用

            // 价格倒序排列
            // 查询可推送的所有 机构任务
            List<MerchantTaskInfo> taskInfoList0 = merchantTaskInfoMapper.getAllApiBEnableTask();

            List<MerchantTaskInfo> taskInfoList = taskInfoList0.stream().sorted(Comparator.comparing(MerchantTaskInfo::getPriceAmount).reversed()).collect(Collectors.toList());
            // 机构任务过滤，筛选可推送的任务
            for (MerchantTaskInfo merchantTaskInfo : taskInfoList) {
                try {
                    FilterHandlerResult filterResult = dataFilterHandleService.execMerchantFilter(merchantTaskInfo, memberSourceInfo);
                    log.info("【商户任务过滤】过滤结束【taskId】{}【uid】{}【filterResult】{}",
                            merchantTaskInfo.getId(), memberSourceInfo.getUid(), JSON.toJSONString(filterResult));
                    // 过滤成功，且拿到价格最高的推送任务（同一个商户）
                    if (filterResult.isSuccess() &&
                            !canMatchMerchantSet.contains(merchantTaskInfo.getInfoId())) {

                        canMatchMerchantSet.add(merchantTaskInfo.getInfoId());
                        resultTaskList.add(merchantTaskInfo);
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                    String message = StrUtil.format("【uid】:{}；【taskId】:{};【infoId】:{};",
                            memberSourceInfo.getUid(), merchantTaskInfo.getId(), merchantTaskInfo.getInfoId());
                    notifyExceptionService.notifyNoticeInfo("MERCHANT2", "商户任务过滤异常2", message, exception);
                }
            }

            CountDownLatch countDownLatch = new CountDownLatch(resultTaskList.size());

            // 可推送的商户任务
            // 进行撞库操作
            List<Future<MatchMerchantInfo>> futureList = new ArrayList<>();
            for (MerchantTaskInfo merchantTaskInfo : resultTaskList) {
                try {

                    MerchantOrderDTO merchantOrderDTO = new MerchantOrderDTO();
                    merchantOrderDTO.setInfoId(merchantTaskInfo.getInfoId());
                    merchantOrderDTO.setTaskId(merchantTaskInfo.getId());
                    merchantOrderDTO.setPriceAmount(merchantTaskInfo.getPriceAmount());
                    merchantOrderDTO.setCostAmount(merchantTaskInfo.getCostAmount());
                    merchantOrderDTO.setPayAmount(merchantTaskInfo.getPayAmount());

                    Future<MatchMerchantInfo> merchantInfoFuture = ThreadUtil.execAsync(new Callable<MatchMerchantInfo>() {
                        @Override
                        public MatchMerchantInfo call() throws Exception {

                            MatchMerchantInfo matchMerchantInfo = merchantBaseInfoService.matchWithMerchant(merchantOrderDTO, memberSourceInfo);

                            countDownLatch.countDown();
                            return matchMerchantInfo;
                        }
                    });

                    futureList.add(merchantInfoFuture);

                } catch (Exception exception) {
                    exception.printStackTrace();
                    String message = StrUtil.format("【uid】:{}；【taskId】:{};【infoId】:{};",
                            memberSourceInfo.getUid(), merchantTaskInfo.getId(), merchantTaskInfo.getInfoId());
                    notifyExceptionService.notifyNoticeInfo("MERCHANT", "商户任务推送异常", message, exception);
                }
            }

            countDownLatch.await(5, TimeUnit.SECONDS);

            for (Future<MatchMerchantInfo> merchantInfoFuture : futureList) {
                if (merchantInfoFuture.isDone()) {
                    try {
                        MatchMerchantInfo merchantInfo = merchantInfoFuture.get();
                        if (merchantInfo.isMatchSuccess()) {
                            merchantInfoList.add(merchantInfo);
                            continue;
                        }
                    } catch (Exception exception) {
                        exception.printStackTrace();
                        String message = StrUtil.format("【uid】:{}；", memberSourceInfo.getUid());
                        notifyExceptionService.notifyNoticeInfo("MERCHANT_EXEC_SELF", "商户任务推送异步异常", message, exception);
                    }
                }
            }

            return merchantInfoList;
        } catch (Exception exception) {
            exception.printStackTrace();
            String message = StrUtil.format("【uid】:{}", memberSourceInfo.getUid());
            notifyExceptionService.notifyNoticeInfo("MERCHANT", "商户任务推送异常", message, exception);
        }
        return merchantInfoList;
    }

    /**
     * 获取API  和 CRM 的推送订单信息
     */
    public List<MatchMerchantInfo> getApiAndCrmPushInfo1(MemberSourceInfo memberSourceInfo) {

        List<MatchMerchantInfo> merchantInfoList = new ArrayList<>();
        try {

            List<MerchantTaskInfo> resultTaskList = new ArrayList<>();
            Set<Integer> canMatchMerchantSet = new HashSet<>();// 过滤同一个商户的作用

            // 价格倒序排列
            List<MerchantTaskInfo> taskInfoList0 = merchantTaskInfoMapper.getAllEnableTask();
            // todo 任务过滤
            List<MerchantTaskInfo> taskInfoList =
                    taskInfoList0.stream()
                            // 不能推给apib
                            .filter(o1 -> !StrUtil.equals(InfoTypeEnum.APIB.getValue(), o1.getInfoType()))
                            // 价格倒序
                            .sorted(Comparator.comparing(MerchantTaskInfo::getPriceAmount).reversed())
                            .collect(Collectors.toList());

            // 机构任务过滤，筛选可推送的任务
            for (MerchantTaskInfo merchantTaskInfo : taskInfoList) {
                try {
                    FilterHandlerResult filterResult = dataFilterHandleService.execMerchantFilter(merchantTaskInfo, memberSourceInfo);
                    log.info("【商户任务过滤】过滤结束【taskId】{}【uid】{}【filterResult】{}",
                            merchantTaskInfo.getId(), memberSourceInfo.getUid(), JSON.toJSONString(filterResult));
                    // 过滤成功，且拿到价格最高的推送任务（同一个商户）
                    if (filterResult.isSuccess() &&
                            !canMatchMerchantSet.contains(merchantTaskInfo.getInfoId())) {

                        canMatchMerchantSet.add(merchantTaskInfo.getInfoId());
                        resultTaskList.add(merchantTaskInfo);
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                    String message = StrUtil.format("【uid】:{}；【taskId】:{};【infoId】:{};",
                            memberSourceInfo.getUid(), merchantTaskInfo.getId(), merchantTaskInfo.getInfoId());
                    notifyExceptionService.notifyNoticeInfo("MERCHANT3", "商户任务过滤异常3", message, exception);
                }
            }

            CountDownLatch countDownLatch = new CountDownLatch(resultTaskList.size());

            // 可推送的商户任务
            // 进行撞库操作
            List<Future<MatchMerchantInfo>> futureList = new ArrayList<>();
            for (MerchantTaskInfo merchantTaskInfo : resultTaskList) {
                try {

                    MerchantOrderDTO merchantOrderDTO = new MerchantOrderDTO();
                    merchantOrderDTO.setInfoId(merchantTaskInfo.getInfoId());
                    merchantOrderDTO.setTaskId(merchantTaskInfo.getId());
                    merchantOrderDTO.setPriceAmount(merchantTaskInfo.getPriceAmount());
                    merchantOrderDTO.setCostAmount(merchantTaskInfo.getCostAmount());
                    merchantOrderDTO.setPayAmount(merchantTaskInfo.getPayAmount());

                    Future<MatchMerchantInfo> merchantInfoFuture = ThreadUtil.execAsync(new Callable<MatchMerchantInfo>() {
                        @Override
                        public MatchMerchantInfo call() throws Exception {
                            MatchMerchantInfo matchMerchantInfo = merchantBaseInfoService.matchWithMerchant(merchantOrderDTO, memberSourceInfo);

                            countDownLatch.countDown();
                            return matchMerchantInfo;
                        }
                    });

                    futureList.add(merchantInfoFuture);

                } catch (Exception exception) {
                    exception.printStackTrace();
                    String message = StrUtil.format("【uid】:{}；【taskId】:{};【infoId】:{};",
                            memberSourceInfo.getUid(), merchantTaskInfo.getId(), merchantTaskInfo.getInfoId());
                    notifyExceptionService.notifyNoticeInfo("MERCHANT", "商户任务推送异常", message, exception);
                }
            }

            countDownLatch.await(3, TimeUnit.SECONDS);

            for (Future<MatchMerchantInfo> merchantInfoFuture : futureList) {
                if (merchantInfoFuture.isDone()) {
                    try {
                        MatchMerchantInfo merchantInfo = merchantInfoFuture.get();
                        if (merchantInfo.isMatchSuccess()) {
                            merchantInfoList.add(merchantInfo);
                            continue;
                        }
                    } catch (Exception exception) {
                        exception.printStackTrace();
                        String message = StrUtil.format("【uid】:{}；", memberSourceInfo.getUid());
                        notifyExceptionService.notifyNoticeInfo("MERCHANT_EXEC_SELF", "商户任务推送异步异常", message, exception);
                    }
                }
            }

            return merchantInfoList;
        } catch (Exception exception) {
            exception.printStackTrace();
            String message = StrUtil.format("【uid】:{}", memberSourceInfo.getUid());
            notifyExceptionService.notifyNoticeInfo("MERCHANT", "商户任务推送异常", message, exception);
        }
        return merchantInfoList;
    }

    public static void main(String[] args) {

        List<MerchantTaskInfo> taskInfoList = new ArrayList<>();

        for (int i = 0; i <10; i++) {
            MerchantTaskInfo merchantTaskInfo = new MerchantTaskInfo();
            merchantTaskInfo.setPriceAmount(new BigDecimal(RandomUtil.randomInt(1000)));

            taskInfoList.add(merchantTaskInfo);
        }

        List<MerchantTaskInfo> collect = taskInfoList.stream().sorted(Comparator.comparing(MerchantTaskInfo::getPriceAmount).reversed()).collect(Collectors.toList());
        List<BigDecimal> collect1 = collect.stream().map(o1 -> o1.getPriceAmount()).collect(Collectors.toList());

        System.out.println(JSON.toJSONString(collect1));
    }

}
